/*
 *  lib-smv: Matrix - Vector Library targeted to Structural Mechanics Problems
 *  Copyright (C) 2006-2008  St.Brcic, Lj.Zugic
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/** @file iArrays.h
 *  @brief Definition of iVector and iMatrix classes of int numbers 
 */

#ifndef _iARRAYS_H
#define _iARRAYS_H

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <cmath>
#include <string>

using namespace std;

namespace smv_lib
{

//---------- forward declaration
class iMatrix;

//------------------------------------------------------------------------
/**
** \brief class iVector of integer numbers
**
**      iVECTOR: VECTOR class of int numbers
**  Constructors: 
**  (1) empty (default) constructor: (size is assigned as default value 2, 
**      name is given as "iVECTOR", but data should be given)
**  (2) constructor with a size 'n' and all elements 'd' (name is not given)
**  (3) constructor with a size 'n' and a given Name 
**  (4) constructor form a vector file (5) copy constructor
**/
//-------------------------------------------------------------------------
class iVector
{
  private:
    //! good for matrix-vector manipulation
    friend class iMatrix;
    //! array of int values
    int *data;
    //! number of vector elements
    int len;
    //! input stream
    ifstream in;
    //! output stream
    ofstream out;
    //! name of the iVector
    string Name;
    //! true if the Name is given, false for default name VECTOR
    bool isNameGiven;

  public:
    //! empty (default) constructors
    iVector();
    //! Vector with 'n' int elements of value 'd'
    iVector(int n, int d = 0);
    //! Vector with given length 'n' and a name
    iVector(int n, string name);
    //! construct a Vector from a file
    iVector(const char* file);
    //! copy constructor
    iVector(const iVector& original);
    //! destructor
    ~iVector();

    //! assignment operator
    iVector& operator = (const iVector &original);
    // -------------------- get and set vector elements
    //! set an element no 'i' (zero based, operator form)
    int& operator [] (int i);
    //! get an element
    const int& operator[] (int i) const;
    //------------------- get and set functions
    //! get number of elements
    const int getLen() const { return len; }
    //! get element no 'i' (zero based)
    const int getData(int i) const;
    //! get the name
    const string getName() const { return Name; }
    //! set length of a Vector
    void setSize(int n) { len = n; }
    //! set element no i with data 'd'
    void setData(int i, int d);
    //! set the name
    void setName(string name);

    //------------------- basic linear algebra - operator functions 
    //                    (better use equivalent functions)
    //! Operator '+' iVector b = self + v
    iVector operator + (const iVector& v);
    //! Operator '-' iVector b = self - v
    iVector operator - (const iVector& v);
    //! Operator '*' with an int: iVector v = self * s;
    iVector operator * ( int s );
    //! scalar product with a vector: s = self * v
    const int operator * ( const iVector& v ) const;
    //! Operator '+=' iVector self = self + v
    iVector& operator += ( const iVector& v );
    //! Operator '-=' iVector self = self - v
    iVector& operator -= ( const iVector& v );
    //! Operator '*=' iVector self = self * s
    iVector& operator *= ( int s );

    //! is self == v ? (true if equal, the names are not important)
    bool operator == (const iVector& v);

    //------------------- basic linear algebra - equivalent functions
    //! Operator '+' iVector b = self + v
    iVector Add(const iVector& v); 
    //!  Operator '-' iVector b = self - v
    iVector Sub(const iVector& v);
    //! Operator '*' with an int: iVector v = self * s;
    iVector Dot( int s );
    //! scalar product with a vector: s = self * v
    const int Dot( const iVector& v ) const;
    //! outer product with a vector
    iMatrix OuterDot( const iVector& v );
    //! Add sub-vector into the vector (add to the old content)
    iVector& addSubVector( int i, const iVector& Sub );
    //! Take sub-vector from a given vector
    iVector getSubVector( int i, int subLen );

    //------------------- arithmetic operations
    //! change the size of a Vector
    void Resize(int n);
    //! make all elements equal to zeroes
    void Zero(void);
    //! max element in a Vector
    const int Max(void) const;
    //! min element in a Vector
    const int Min(void) const;
    //! mean value of all elements
    const double Mean(void) const;
    //! norm of Self vector (intensity)
    const double Norm(void) const;
    //------------------- console output
    //! print all in one row
    void rPrint(void);
    //! print each element in a row
    void Print(void);
    //------------------- file I/O
    //! read from predefined file "Name.txt"
    iVector Read(void);
    //! write to predefined file  "Name.txt"
    void Write(void);
    //! read from a file
    iVector ReadFrom(const char* file);
    //! write to a file (L entries in a line)
    void WriteTo(const char* file, int L = 20);
    //------------------- stream I/O
    //! output stream
    friend ostream& operator << (ostream& s, const iVector& v);
};

//============================================ global iVector operator functions
//! Addition of two vectors: c = a + b
iVector operator + (const iVector& a, const iVector& b);
//! Subtraction of two vectors: c = a - b
iVector operator - (const iVector& a, const iVector& b);
//! dot product of two vectors: d = v1 * v2
int Dot(const iVector& v1, const iVector& v2);  
//! dot product of two vectors: d = v1 * v2
int operator * (const iVector& v1, const iVector& v2); 
//! Product with int scalar: Vector b = s * v
iVector operator * (int s, const iVector& v);
//! Product with int scalar: Vector b = v * s
iVector operator * (const iVector& v, int s);
//! norm of a vector v
double Norm(const iVector& v);
////! output stream
//ostream& operator << (ostream& s, const iVector& v);

//-----------------------------------------------------------------------
/**
** \brief class iMatrix of integer numbers
**
**     iMATRIX: MATRIX class of int numbers
**
**/
//-----------------------------------------------------------------------
class iMatrix
{
  private:
    //! Matrix data (Vector of rows m)
    iVector* m;
    //! number of rows and columns
    int rows,cols;
    //! input stream
    ifstream in;
    //! output stream
    ofstream out;
    //! name of the Matrix
    string Name;
    //! true if the Name is given, false for default name MATRIX
    bool isNameGiven;

  public:
    //! empty (default) constructor
    iMatrix();
    //! construct a Matrix with given rows, columns and all elements
    iMatrix(int r, int c, int dat = 0);
    //! construct a Matrix with given rows, columns and a name
    iMatrix(int r, int c, string name);
    //! construct a Matrix from a file
    iMatrix(const char* file);
    //! copy constructor
    iMatrix(const iMatrix& s);
    //! destructor
    ~iMatrix();
    //! assignment operator
    iMatrix& operator = (const iMatrix& s);

    //get and set functions
    //! get number of rows
    const int getRows() const { return rows; }
    //! get number of columns
    const int getCols() const { return cols; }
    //! get element (i,j) - zero based
    const int getElement(int i, int j) const;
    //! get elements in a row 'i' of a Matrix
    const iVector getRowData(int i) const;
    //! get elements in a column 'j' of a Matrix
    const iVector getColData(int j) const;
    //! get the name of a Matrix
    const string getName() const { return Name; }
    //! set number of rows
    void setRows(int r) { rows = r; }
    //! set numer of columns
    void setCols(int c) { cols = c; }
    //! set the value 'val' to row 'i' and column 'j'
    void setElement(int i, int j, int val);
    //! set all data in a row 'i' with Vector 'v'
    void setRowData(int i, const iVector& v);
    //! set all data in a column 'j' with Vector 'v'
    void setColData(int j, const iVector& v);
    //! set a name to the Matrix
    void setName(const string name);

    //------------------- arithmetic operations
    //! the sum of elements in a row "i"
    const int RowSum(int i) const;
    //! the sum of elements in a column "j"
    const int ColSum(int j) const;
    //! Matrix is assigned with all zero elements
    void Zero(void);
    //! Matrix becomes a unitary matrix
    void Identity(void);
    //! Matrix becomes diagonal (all eleemnts are the same: 'd')
    void Diagonal(int d);
    //! Matrix becomes diagonal (elements are equal to Vector 'v')
    void Diagonal(const iVector& v);
    //! Insert sub-matrix into the matrix (replace the old content)
    iMatrix& insertSubMatrix(int i, int j, const iMatrix& Sub);
    //! Add sub-matrix into the matrix (add to the old content)
    iMatrix& addSubMatrix(int i, int j, const iMatrix& Sub);
    //! Take sub-matrix from a given matrix
    iMatrix getSubMatrix(int i, int j, int subRow, int subCol);

    //------------------- basic linear algebra - operator functions
    //! Matrix B = Matrix self + Matrix A
    iMatrix operator + (const iMatrix& A);
    //! Matrix B = Matrix self - Matrix A
    iMatrix operator - (const iMatrix& A);
    //! Matrix B = Matrix self * int s
    iMatrix operator * (int s);
    //! Vector b = Matrix self * Vector v
    iVector operator * (const iVector& v);
    //! Matrix B = Matrix self * Matrix A
    iMatrix operator * (const iMatrix& A);
    //! transpose of Matrix SELF
    iMatrix operator ~ ();

  private:
    //------------------- basic linear algebra - equivalent private functions
    //! Matrix B = Matrix self + Matrix A
    iMatrix Add(const iMatrix& A);
    //! Matrix B = Matrix self - Matrix A
    iMatrix Sub(const iMatrix& A);
    //! Vector b = Matrix self * Vector v
    iVector Dot(const iVector& v);
    //! Matrix B = Matrix self * int s
    iMatrix Dot(int s);
    //! Matrix B = Matrix self * Matrix A
    iMatrix Dot(const iMatrix& A);
    //! transpose of Matrix SELF
    iMatrix Tra();

  public:
    //------------------- console output
    //! prints entries on a single line
    void Print(void);
    //! prints entries line by line
    void pPrint(void);
    //------------------- file I/O
    //! read from predefined file "Name.txt"
    iMatrix Read(void);
    //! write to predefined file  "Name.txt"
    void Write(void);
    //! read form a file
    iMatrix ReadFrom(const char* file);
    //! write to a file (L entries in a line)
    void WriteTo(const char* file, int L = 20);
    //------------------- stream I/O
    friend ostream& operator << (ostream& s, const iMatrix& M);

};

//------------------ global iMatrix operator functions
//! Multiplication of matrix and a scalar: B = s * A
iMatrix operator * (int s, const iMatrix& A);
//! Multiplication of matrix and a scalar: B = A * s
iMatrix operator * (const iMatrix& A, int s);
//! Multiplication of a matrix and a vector: c = A * b
iVector operator * (const iMatrix& A, const iVector b);
//! Multiplication of two matrices: C = A * B
iMatrix operator * (const iMatrix& A, const iMatrix& B);
//! Addition of two matrices: C = A + B
iMatrix operator + (const iMatrix& A, const iMatrix& B);
//! Subtraction of two matrices: C = A - B
iMatrix operator + (const iMatrix& A, const iMatrix& B);
////! output stream
//ostream& operator << (ostream& s, const iMatrix& M);

}   // end of namespace smv_lib

#endif   // _iARRAYS_H

//================================ end of file
